}
}
+static GList *
+shell_generic_container_get_focus_chain (StContainer *container)
+{
+ ShellGenericContainer *self = SHELL_GENERIC_CONTAINER (container);
+ GList *children, *focus_chain;
+
+ focus_chain = NULL;
+ for (children = st_container_get_children_list (container); children; children = children->next)
+ {
+ ClutterActor *child = children->data;
+
+ if (CLUTTER_ACTOR_IS_VISIBLE (child) &&
+ !shell_generic_container_get_skip_paint (self, child))
+ focus_chain = g_list_prepend (focus_chain, child);
+ }
+
+ return g_list_reverse (focus_chain);
+}
+
/**
* shell_generic_container_get_n_skip_paint:
* @self: A #ShellGenericContainer
{
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
ClutterActorClass *actor_class = CLUTTER_ACTOR_CLASS (klass);
+ StContainerClass *container_class = ST_CONTAINER_CLASS (klass);
gobject_class->finalize = shell_generic_container_finalize;
actor_class->paint = shell_generic_container_paint;
actor_class->pick = shell_generic_container_pick;
+ container_class->get_focus_chain = shell_generic_container_get_focus_chain;
+
shell_generic_container_signals[GET_PREFERRED_WIDTH] =
g_signal_new ("get-preferred-width",
G_TYPE_FROM_CLASS (klass),
G_OBJECT_CLASS (st_bin_parent_class)->dispose (gobject);
}
+static gboolean
+st_bin_navigate_focus (StWidget *widget,
+ ClutterActor *from,
+ GtkDirectionType direction)
+{
+ StBinPrivate *priv = ST_BIN (widget)->priv;
+ ClutterActor *bin_actor = CLUTTER_ACTOR (widget);
+
+ if (st_widget_get_can_focus (widget))
+ {
+ if (from && clutter_actor_contains (bin_actor, from))
+ return FALSE;
+
+ clutter_actor_grab_key_focus (bin_actor);
+ return TRUE;
+ }
+ else if (priv->child && ST_IS_WIDGET (priv->child))
+ return st_widget_navigate_focus (ST_WIDGET (priv->child), from, direction, FALSE);
+ else
+ return FALSE;
+}
+
static void
st_bin_set_property (GObject *gobject,
guint prop_id,
{
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
ClutterActorClass *actor_class = CLUTTER_ACTOR_CLASS (klass);
+ StWidgetClass *widget_class = ST_WIDGET_CLASS (klass);
GParamSpec *pspec;
g_type_class_add_private (klass, sizeof (StBinPrivate));
actor_class->paint = st_bin_paint;
actor_class->pick = st_bin_pick;
+ widget_class->navigate_focus = st_bin_navigate_focus;
+
/**
* StBin:child:
*
#include "config.h"
#endif
+#include <stdlib.h>
+
#include "st-container.h"
#define ST_CONTAINER_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj),ST_TYPE_CONTAINER, StContainerPrivate))
return container->priv->children;
}
+static GList *
+st_container_real_get_focus_chain (StContainer *container)
+{
+ GList *chain, *children;
+
+ chain = NULL;
+ for (children = container->priv->children; children; children = children->next)
+ {
+ ClutterActor *child = children->data;
+
+ if (CLUTTER_ACTOR_IS_VISIBLE (child))
+ chain = g_list_prepend (chain, child);
+ }
+
+ return g_list_reverse (chain);
+}
+
+/**
+ * st_container_get_focus_chain:
+ * @container: An #StContainer
+ *
+ * Gets a list of the focusable children of @container, in "Tab"
+ * order. By default, this returns all visible
+ * (as in CLUTTER_ACTOR_IS_VISIBLE()) children of @container.
+ *
+ * Returns: (element-type Clutter.Actor) (transfer container):
+ * @container's focusable children
+ */
+GList *
+st_container_get_focus_chain (StContainer *container)
+{
+ return ST_CONTAINER_GET_CLASS (container)->get_focus_chain (container);
+}
+
static gint
sort_z_order (gconstpointer a,
gconstpointer b)
G_OBJECT_CLASS (st_container_parent_class)->dispose (object);
}
+/* filter @children to contain only only actors that overlap @rbox
+ * when moving in @direction. (Assuming no transformations.)
+ */
+static GList *
+filter_by_position (GList *children,
+ ClutterActorBox *rbox,
+ GtkDirectionType direction)
+{
+ ClutterActorBox cbox;
+ GList *l, *ret;
+ ClutterActor *child;
+
+ for (l = children, ret = NULL; l; l = l->next)
+ {
+ child = l->data;
+ clutter_actor_get_allocation_box (child, &cbox);
+
+ /* Filter out children if they are in the wrong direction from
+ * @rbox, or if they don't overlap it.
+ */
+ switch (direction)
+ {
+ case GTK_DIR_UP:
+ if (cbox.y2 > rbox->y1)
+ continue;
+ if (cbox.x1 >= rbox->x2 || cbox.x2 <= rbox->x1)
+ continue;
+ break;
+
+ case GTK_DIR_DOWN:
+ if (cbox.y1 < rbox->y2)
+ continue;
+ if (cbox.x1 >= rbox->x2 || cbox.x2 <= rbox->x1)
+ continue;
+ break;
+
+ case GTK_DIR_LEFT:
+ if (cbox.x2 > rbox->x1)
+ continue;
+ if (cbox.y1 >= rbox->y2 || cbox.y2 <= rbox->y1)
+ continue;
+ break;
+
+ case GTK_DIR_RIGHT:
+ if (cbox.x1 < rbox->x2)
+ continue;
+ if (cbox.y1 >= rbox->y2 || cbox.y2 <= rbox->y1)
+ continue;
+ break;
+
+ default:
+ g_return_val_if_reached (NULL);
+ }
+
+ ret = g_list_prepend (ret, child);
+ }
+
+ g_list_free (children);
+ return ret;
+}
+
+typedef struct {
+ GtkDirectionType direction;
+ ClutterActorBox box;
+} StContainerChildSortData;
+
+static int
+sort_by_position (gconstpointer a,
+ gconstpointer b,
+ gpointer user_data)
+{
+ ClutterActor *actor_a = (ClutterActor *)a;
+ ClutterActor *actor_b = (ClutterActor *)b;
+ StContainerChildSortData *sort_data = user_data;
+ GtkDirectionType direction = sort_data->direction;
+ ClutterActorBox abox, bbox;
+ int ax, ay, bx, by;
+ int cmp, fmid;
+
+ /* Determine the relationship, relative to motion in @direction, of
+ * the center points of the two actors. Eg, for %GTK_DIR_UP, we
+ * return a negative number if @actor_a's center is below @actor_b's
+ * center, and postive if vice versa, which will result in an
+ * overall list sorted bottom-to-top.
+ */
+
+ clutter_actor_get_allocation_box (actor_a, &abox);
+ ax = (int)(abox.x1 + abox.x2) / 2;
+ ay = (int)(abox.y1 + abox.y2) / 2;
+ clutter_actor_get_allocation_box (actor_b, &bbox);
+ bx = (int)(bbox.x1 + bbox.x2) / 2;
+ by = (int)(bbox.y1 + bbox.y2) / 2;
+
+ switch (direction)
+ {
+ case GTK_DIR_UP:
+ cmp = by - ay;
+ break;
+ case GTK_DIR_DOWN:
+ cmp = ay - by;
+ break;
+ case GTK_DIR_LEFT:
+ cmp = bx - ax;
+ break;
+ case GTK_DIR_RIGHT:
+ cmp = ax - bx;
+ break;
+ default:
+ g_return_val_if_reached (0);
+ }
+
+ if (cmp)
+ return cmp;
+
+ /* If two actors have the same center on the axis being sorted,
+ * prefer the one that is closer to the center of the current focus
+ * actor on the other axis. Eg, for %GTK_DIR_UP, prefer whichever
+ * of @actor_a and @actor_b has a horizontal center closest to the
+ * current focus actor's horizontal center.
+ *
+ * (This matches GTK's behavior.)
+ */
+ switch (direction)
+ {
+ case GTK_DIR_UP:
+ case GTK_DIR_DOWN:
+ fmid = (int)(sort_data->box.x1 + sort_data->box.x2) / 2;
+ return abs (ax - fmid) - abs (bx - fmid);
+ case GTK_DIR_LEFT:
+ case GTK_DIR_RIGHT:
+ fmid = (int)(sort_data->box.y1 + sort_data->box.y2) / 2;
+ return abs (ay - fmid) - abs (by - fmid);
+ default:
+ g_return_val_if_reached (0);
+ }
+}
+
+static gboolean
+st_container_navigate_focus (StWidget *widget,
+ ClutterActor *from,
+ GtkDirectionType direction)
+{
+ StContainer *container = ST_CONTAINER (widget);
+ ClutterActor *container_actor, *focus_child;
+ GList *children, *l;
+
+ container_actor = CLUTTER_ACTOR (widget);
+ if (from == container_actor)
+ return FALSE;
+
+ /* Figure out if @from is a descendant of @container, and if so,
+ * set @focus_child to the immediate child of @container that
+ * contains (or *is*) @from.
+ */
+ focus_child = from;
+ while (focus_child && clutter_actor_get_parent (focus_child) != container_actor)
+ focus_child = clutter_actor_get_parent (focus_child);
+
+ if (st_widget_get_can_focus (widget))
+ {
+ if (!focus_child)
+ {
+ /* Accept focus from outside */
+ clutter_actor_grab_key_focus (container_actor);
+ return TRUE;
+ }
+ else
+ {
+ /* Yield focus from within: since @container itself is
+ * focusable we don't allow the focus to be navigated
+ * within @container.
+ */
+ return FALSE;
+ }
+ }
+
+ /* See if we can navigate within @focus_child */
+ if (focus_child && ST_IS_WIDGET (focus_child))
+ {
+ if (st_widget_navigate_focus (ST_WIDGET (focus_child), from, direction, FALSE))
+ return TRUE;
+ }
+
+ /* At this point we know that we want to navigate focus to one of
+ * @container's immediate children; the next one after @focus_child,
+ * or the first one if @focus_child is %NULL. (With "next" and
+ * "first" being determined by @direction.)
+ */
+
+ children = st_container_get_focus_chain (container);
+ if (direction == GTK_DIR_TAB_FORWARD ||
+ direction == GTK_DIR_TAB_BACKWARD)
+ {
+ if (direction == GTK_DIR_TAB_BACKWARD)
+ children = g_list_reverse (children);
+
+ if (focus_child)
+ {
+ /* Remove focus_child and any earlier children */
+ while (children && children->data != focus_child)
+ children = g_list_delete_link (children, children);
+ if (children)
+ children = g_list_delete_link (children, children);
+ }
+ }
+ else /* direction is an arrow key, not tab */
+ {
+ StContainerChildSortData sort_data;
+
+ /* Compute the allocation box of the previous focused actor, in
+ * @container's coordinate space. If there was no previous focus,
+ * use the coordinates of the appropriate edge of @container.
+ *
+ * Note that all of this code assumes the actors are not
+ * transformed (or at most, they are all scaled by the same
+ * amount). If @container or any of its children is rotated, or
+ * any child is inconsistently scaled, then the focus chain will
+ * probably be unpredictable.
+ */
+ if (from)
+ {
+ if (from == focus_child)
+ clutter_actor_get_allocation_box (focus_child, &sort_data.box);
+ else
+ {
+ float cx, cy, fx, fy, fw, fh;
+
+ clutter_actor_get_transformed_position (CLUTTER_ACTOR (container), &cx, &cy);
+ clutter_actor_get_transformed_position (from, &fx, &fy);
+ clutter_actor_get_transformed_size (from, &fw, &fh);
+
+ sort_data.box.x1 = fx - cx;
+ sort_data.box.x2 = fx - cx + fw;
+ sort_data.box.y1 = fy - cy;
+ sort_data.box.y2 = fy - cy + fh;
+ }
+ }
+ else
+ {
+ clutter_actor_get_allocation_box (CLUTTER_ACTOR (container), &sort_data.box);
+ switch (direction)
+ {
+ case GTK_DIR_UP:
+ sort_data.box.y1 = sort_data.box.y2;
+ break;
+ case GTK_DIR_DOWN:
+ sort_data.box.y2 = sort_data.box.y1;
+ break;
+ case GTK_DIR_LEFT:
+ sort_data.box.x1 = sort_data.box.x2;
+ break;
+ case GTK_DIR_RIGHT:
+ sort_data.box.x2 = sort_data.box.x1;
+ break;
+ default:
+ g_warn_if_reached ();
+ }
+ }
+ sort_data.direction = direction;
+
+ if (focus_child)
+ children = filter_by_position (children, &sort_data.box, direction);
+ if (children)
+ children = g_list_sort_with_data (children, sort_by_position, &sort_data);
+ }
+
+ /* Now try each child in turn */
+ for (l = children; l; l = l->next)
+ {
+ if (ST_IS_WIDGET (l->data))
+ {
+ if (st_widget_navigate_focus (l->data, from, direction, FALSE))
+ {
+ g_list_free (children);
+ return TRUE;
+ }
+ }
+ }
+
+ g_list_free (children);
+ return FALSE;
+}
+
static void
clutter_container_iface_init (ClutterContainerIface *iface)
{
st_container_class_init (StContainerClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ StWidgetClass *widget_class = ST_WIDGET_CLASS (klass);
+ StContainerClass *container_class = ST_CONTAINER_CLASS (klass);
g_type_class_add_private (klass, sizeof (StContainerPrivate));
object_class->dispose = st_container_dispose;
+
+ widget_class->navigate_focus = st_container_navigate_focus;
+
+ container_class->get_focus_chain = st_container_real_get_focus_chain;
}
struct _StContainerClass {
StWidgetClass parent_class;
+
+ GList * (*get_focus_chain) (StContainer *container);
};
GType st_container_get_type (void) G_GNUC_CONST;
void st_container_remove_all (StContainer *container);
void st_container_destroy_children (StContainer *container);
+GList * st_container_get_focus_chain (StContainer *container);
+
/* Only to be used by subclasses of StContainer */
void st_container_move_child (StContainer *container,
ClutterActor *actor,
int pos);
-GList *st_container_get_children_list (StContainer *container);
+GList * st_container_get_children_list (StContainer *container);
G_END_DECLS
ST_WIDGET_CLASS (st_entry_parent_class)->style_changed (self);
}
+static gboolean
+st_entry_navigate_focus (StWidget *widget,
+ ClutterActor *from,
+ GtkDirectionType direction)
+{
+ StEntryPrivate *priv = ST_ENTRY_PRIV (widget);
+
+ /* This is basically the same as st_widget_real_navigate_focus(),
+ * except that widget is behaving as a proxy for priv->entry (which
+ * isn't an StWidget and so has no can-focus flag of its own).
+ */
+
+ if (from == priv->entry)
+ return FALSE;
+ else if (st_widget_get_can_focus (widget))
+ {
+ clutter_actor_grab_key_focus (priv->entry);
+ return TRUE;
+ }
+ else
+ return FALSE;
+}
+
static void
st_entry_get_preferred_width (ClutterActor *actor,
gfloat for_height,
actor_class->leave_event = st_entry_leave_event;
widget_class->style_changed = st_entry_style_changed;
+ widget_class->navigate_focus = st_entry_navigate_focus;
pspec = g_param_spec_object ("clutter-text",
"Clutter Text",
}
static void
-st_overflow_box_internal_paint (StOverflowBox *box)
+visible_children_iter_init (StOverflowBox *box,
+ GList **iter,
+ int *n)
+{
+ *iter = st_container_get_children_list (ST_CONTAINER (box));
+ *n = 0;
+}
+
+static ClutterActor *
+visible_children_iter (StOverflowBox *box,
+ GList **iter,
+ int *n)
{
StOverflowBoxPrivate *priv = box->priv;
- GList *l, *children;
- int i;
+ GList *l;
- i = 0;
- children = st_container_get_children_list (ST_CONTAINER (box));
- for (l = children; i < priv->n_visible && l; l = l->next)
+ for (l = *iter; *n < priv->n_visible && l; l = l->next)
{
ClutterActor *child = (ClutterActor*) l->data;
if (!CLUTTER_ACTOR_IS_VISIBLE (child))
continue;
if (!clutter_actor_get_fixed_position_set (child))
- i++;
+ (*n)++;
- clutter_actor_paint (child);
+ *iter = l->next;
+ return child;
}
- for (;l; l = l->next)
+ for (; l; l = l->next)
{
ClutterActor *child = (ClutterActor*) l->data;
continue;
if (clutter_actor_get_fixed_position_set (child))
- clutter_actor_paint (child);
+ {
+ *iter = l->next;
+ return child;
+ }
}
+
+ return NULL;
+}
+
+static void
+st_overflow_box_internal_paint (StOverflowBox *box)
+{
+ ClutterActor *child;
+ GList *children;
+ int n;
+
+ visible_children_iter_init (box, &children, &n);
+ while ((child = visible_children_iter (box, &children, &n)))
+ clutter_actor_paint (child);
}
static void
ST_WIDGET_CLASS (st_overflow_box_parent_class)->style_changed (self);
}
+static GList *
+st_overflow_box_get_focus_chain (StContainer *container)
+{
+ StOverflowBox *box = ST_OVERFLOW_BOX (container);
+ ClutterActor *child;
+ GList *children, *focus_chain;
+ int n;
+
+ focus_chain = NULL;
+ visible_children_iter_init (box, &children, &n);
+ while ((child = visible_children_iter (box, &children, &n)))
+ focus_chain = g_list_prepend (focus_chain, child);
+
+ return g_list_reverse (focus_chain);
+}
+
static void
st_overflow_box_class_init (StOverflowBoxClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
ClutterActorClass *actor_class = CLUTTER_ACTOR_CLASS (klass);
StWidgetClass *widget_class = ST_WIDGET_CLASS (klass);
+ StContainerClass *container_class = ST_CONTAINER_CLASS (klass);
GParamSpec *pspec;
g_type_class_add_private (klass, sizeof (StOverflowBoxPrivate));
widget_class->style_changed = st_overflow_box_style_changed;
+ container_class->get_focus_chain = st_overflow_box_get_focus_chain;
+
pspec = g_param_spec_uint ("min-children",
"Min Children",
"The actor will request a minimum size large enough to include this many children",
gboolean draw_border_internal : 1;
gboolean track_hover : 1;
gboolean hover : 1;
+ gboolean can_focus : 1;
StTooltip *tooltip;
PROP_HAS_TOOLTIP,
PROP_TOOLTIP_TEXT,
PROP_TRACK_HOVER,
- PROP_HOVER
+ PROP_HOVER,
+ PROP_CAN_FOCUS
};
enum
static void st_widget_recompute_style (StWidget *widget,
StThemeNode *old_theme_node);
+static gboolean st_widget_real_navigate_focus (StWidget *widget,
+ ClutterActor *from,
+ GtkDirectionType direction);
static void
st_widget_set_property (GObject *gobject,
st_widget_set_hover (actor, g_value_get_boolean (value));
break;
+ case PROP_CAN_FOCUS:
+ st_widget_set_can_focus (actor, g_value_get_boolean (value));
+ break;
+
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
break;
g_value_set_boolean (value, priv->hover);
break;
+ case PROP_CAN_FOCUS:
+ g_value_set_boolean (value, priv->can_focus);
+ break;
+
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
break;
return FALSE;
}
+static void
+st_widget_key_focus_in (ClutterActor *actor)
+{
+ StWidget *widget = ST_WIDGET (actor);
+
+ st_widget_add_style_pseudo_class (widget, "focus");
+}
+
+static void
+st_widget_key_focus_out (ClutterActor *actor)
+{
+ StWidget *widget = ST_WIDGET (actor);
+
+ st_widget_remove_style_pseudo_class (widget, "focus");
+}
+
static void
st_widget_hide (ClutterActor *actor)
{
actor_class->enter_event = st_widget_enter;
actor_class->leave_event = st_widget_leave;
+ actor_class->key_focus_in = st_widget_key_focus_in;
+ actor_class->key_focus_out = st_widget_key_focus_out;
actor_class->hide = st_widget_hide;
klass->style_changed = st_widget_real_style_changed;
+ klass->navigate_focus = st_widget_real_navigate_focus;
/**
* StWidget:pseudo-class:
PROP_HOVER,
pspec);
+ /**
+ * StWidget:can-focus:
+ *
+ * Whether or not the widget can be focused via keyboard navigation.
+ */
+ pspec = g_param_spec_boolean ("can-focus",
+ "Can focus",
+ "Whether the widget can be focused via keyboard navigation",
+ FALSE,
+ ST_PARAM_READWRITE);
+ g_object_class_install_property (gobject_class,
+ PROP_CAN_FOCUS,
+ pspec);
+
/**
* StWidget::style-changed:
*
return widget->priv->hover;
}
+/**
+ * st_widget_set_can_focus:
+ * @widget: A #StWidget
+ * @can_focus: %TRUE if the widget can receive keyboard focus
+ * via keyboard navigation
+ *
+ * Marks @widget as being able to receive keyboard focus via
+ * keyboard navigation.
+ */
+void
+st_widget_set_can_focus (StWidget *widget,
+ gboolean can_focus)
+{
+ StWidgetPrivate *priv;
+
+ g_return_if_fail (ST_IS_WIDGET (widget));
+
+ priv = widget->priv;
+
+ if (priv->can_focus != can_focus)
+ {
+ priv->can_focus = can_focus;
+ g_object_notify (G_OBJECT (widget), "can-focus");
+ }
+}
+
+/**
+ * st_widget_get_can_focus:
+ * @widget: A #StWidget
+ *
+ * Returns the current value of the can-focus property. See
+ * st_widget_set_can_focus() for more information.
+ *
+ * Returns: current value of can-focus on @widget
+ */
+gboolean
+st_widget_get_can_focus (StWidget *widget)
+{
+ g_return_val_if_fail (ST_IS_WIDGET (widget), FALSE);
+
+ return widget->priv->can_focus;
+}
+
+static gboolean
+st_widget_real_navigate_focus (StWidget *widget,
+ ClutterActor *from,
+ GtkDirectionType direction)
+{
+ if (widget->priv->can_focus &&
+ CLUTTER_ACTOR (widget) != from)
+ {
+ clutter_actor_grab_key_focus (CLUTTER_ACTOR (widget));
+ return TRUE;
+ }
+ return FALSE;
+}
+
+/**
+ * st_widget_navigate_focus:
+ * @widget: the "top level" container
+ * @from: (allow-none): the actor that the focus is coming from
+ * @direction: the direction focus is moving in
+ * @wrap_around: whether focus should wrap around
+ *
+ * Tries to update the keyboard focus within @widget in response to a
+ * keyboard event.
+ *
+ * If @from is a descendant of @widget, this attempts to move the
+ * keyboard focus to the next descendant of @widget (in the order
+ * implied by @direction) that has the #StWidget:can-focus property
+ * set. If @from is %NULL, or outside of @widget, this attempts to
+ * focus either @widget itself, or its first descendant in the order
+ * implied by @direction.
+ *
+ * If a container type is marked #StWidget:can-focus, the expected
+ * behavior is that it will only take up a single slot on the focus
+ * chain as a whole, rather than allowing navigation between its child
+ * actors (or having a distinction between itself being focused and
+ * one of its children being focused).
+ *
+ * Some widget classes might have slightly different behavior from the
+ * above, where that would make more sense.
+ *
+ * If @wrap_around is %TRUE and @from is a child of @widget, but the
+ * widget has no further children that can accept the focus in the
+ * given direction, then st_widget_navigate_focus() will try a second
+ * time, using a %NULL @from, which should cause it to reset the focus
+ * to the first available widget in the given direction.
+ *
+ * Return value: %TRUE if clutter_actor_grab_key_focus() has been
+ * called on an actor. %FALSE if not.
+ */
+gboolean
+st_widget_navigate_focus (StWidget *widget,
+ ClutterActor *from,
+ GtkDirectionType direction,
+ gboolean wrap_around)
+{
+ g_return_val_if_fail (ST_IS_WIDGET (widget), FALSE);
+
+ if (ST_WIDGET_GET_CLASS (widget)->navigate_focus (widget, from, direction))
+ return TRUE;
+ if (wrap_around && from && clutter_actor_contains (CLUTTER_ACTOR (widget), from))
+ return ST_WIDGET_GET_CLASS (widget)->navigate_focus (widget, NULL, direction);
+ return FALSE;
+}
+
static gboolean
append_actor_text (GString *desc,
ClutterActor *actor)
ClutterActorClass parent_class;
/* vfuncs */
- void (* style_changed) (StWidget *self);
+ void (* style_changed) (StWidget *self);
+ gboolean (* navigate_focus) (StWidget *self,
+ ClutterActor *from,
+ GtkDirectionType direction);
};
GType st_widget_get_type (void) G_GNUC_CONST;
void st_widget_set_direction (StWidget *self,
StTextDirection dir);
+void st_widget_set_can_focus (StWidget *widget,
+ gboolean can_focus);
+gboolean st_widget_get_can_focus (StWidget *widget);
+gboolean st_widget_navigate_focus (StWidget *widget,
+ ClutterActor *from,
+ GtkDirectionType direction,
+ gboolean wrap_around);
+
/* Only to be used by sub-classes of StWidget */
void st_widget_style_changed (StWidget *widget);
StThemeNode * st_widget_get_theme_node (StWidget *widget);